using System;
using System.Collections;
using System.Net.Mail;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.CDS;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.FormsManagement;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.ScriptEngine;
using PHSRAG.Security;
using PHSRAG.Utility;
using ScriptReference=PHSRAG.Insight21.ScriptEngine.ScriptReference;

namespace PHSRAG.Insight21.COI
{
    /// <summary>
    /// COISubmission page allows for validating the COI and submitting it.
    /// This page displays errors, if any, upon validation. 
    /// </summary>
    public partial class COISubmission : BasePage
    {
        #region Nested type: SubmissionStage

        /// <summary>
        /// Enum for the Process status
        /// </summary>
        private enum SubmissionStage
        {
            Submit,
            SubmitComplete,
            None
        }

        #endregion

        #region private variables

        private ICachePolicy cachePolicy;
        private ConflictOfInterest coi;
        private int coiId;
        private ICachePolicy pageCachePolicy;

        #endregion

        #region Private properties

        /// <summary>
        /// Gets the COI object.
        /// If it's not already in the cache, it loads it up based on the coiId passed to the page, and caches the object
        /// </summary>
        private ConflictOfInterest CurrentConflictOfInterest
        {
            get
            {
                string cacheKey = ConflictOfInterest.COIKey;
                coi = cachePolicy.GetCachedObject(cacheKey) as ConflictOfInterest;

                if ((coi == null) || (coiId != coi.Id))
                {
                    coi = new ConflictOfInterest(cachePolicy);
                    coi.Load(DataAccess.GetConnectionString(), coiId);
                    cachePolicy.Cache(cacheKey, coi);
                }
                return coi;
            }
        }

        #endregion

        #region Page Event Handlers

        /// <summary>
        /// Displays controls based on the COI status.
        /// </summary>
        /// <param name="sender">Object that raised the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                annunciator.Message = string.Empty;

                string name = string.Empty;

                Hashtable incomingData = pageCachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;
                if (incomingData != null)
                {
                    if (incomingData.ContainsKey(Keys.FullNameKey))
                    {
                        name = Convert.ToString(incomingData[Keys.FullNameKey]);
                    }

                    if (incomingData.ContainsKey(Keys.COIIdKey))
                    {
                        coiId = Convert.ToInt32(incomingData[Keys.COIIdKey]);
                    }
                    else
                    {
                        throw new Exception("Page is being viewed out of context");
                    }
                }
                else
                {
                    throw new Exception("Page is being viewed out of context");
                }

                breadCrumb.Add(((name.Length > 0) ? string.Format("Submission - {0}", name) : "Submission"),
                    Settings.GetKeyValue("SubModuleNavigation.Humans.COISubmissionURL", ""),
                    Settings.GetKeyValue("BreadCrumb.DetailPageLevel", 2));

                if (CurrentConflictOfInterest.COIType == (int)Constants.COIType.AnnualCycle)
                {
                    if ((CurrentConflictOfInterest.Status == Constants.COIStatus.InProgress) || (CurrentConflictOfInterest.Status == Constants.COIStatus.Start))
                    {
                        SetSubmissionStage(SubmissionStage.Submit);
                    }
                    else
                    {
                        SetSubmissionStage(SubmissionStage.SubmitComplete);
                    }
                }
                else
                {
                    SetSubmissionStage(SubmissionStage.None);
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
            finally
            {
                coiSubNavigation.SelectedLink = "Forms Management";
                coiSubNavigation.AccessLevel = ((UserContext) cachePolicy.GetCachedObject(UserContext.CacheKey)).ModuleRoleBitmask;
            }
        }

        /// <summary>
        /// Registers scripts to hide runningValidation panel / errorgrid panel
        /// </summary>
        /// <param name="e">Arguments associated with the event</param>
        protected override void OnPreRender(EventArgs e)
        {
            try
            {
                base.OnPreRender(e);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        #endregion

        #region Web Form Designer generated code

        /// <summary>
        /// Page Initialization
        /// </summary>
        /// <param name="e">Arguments associated with the event</param>
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);
            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.header.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.coiSubModNavigation.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnCOISubModNavigationNavigate);
            this.breadCrumb.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnBreadCrumbNavigate);
            //this.viewApplication.Click += new ImageClickEventHandler(OnViewReport);
            //this.viewDisclosure.Click += new ImageClickEventHandler(OnViewDisclosure);
            this.submitCOI.Click += new ImageClickEventHandler(OnSubmit);
        }

        #endregion

        #region Private methods

        /// <summary>
        /// Set the User interface according to the COI status
        /// </summary>
        /// <param name="stage">Submission stage enumeration</param>
        /// <param name="args">optional parameter which takes the LogItem arrayList to be displayed .</param>
        private void SetSubmissionStage(SubmissionStage stage, params object[] args)
        {

            switch (stage)
            {
                case SubmissionStage.Submit:
                {
                    submitComplete.Visible = false;

                    viewApplication.Visible = false;
                    viewDisclosure.Visible = false;

                    acknowledgement.Visible = true;
                    break;
                }
                case SubmissionStage.SubmitComplete:
                {
                    submitComplete.Visible = true;
                    acknowledgement.Visible = false;

                    viewApplication.Visible = true;
                    viewDisclosure.Visible = true;
                    break;
                }
                case SubmissionStage.None:
                {
                    submitComplete.Visible = false;
                    viewApplication.Visible = false;
                    viewDisclosure.Visible = false;
                    acknowledgement.Visible = false;
                    break;
                }


            }
        }

        /// <summary>
        /// Removes all the details that are specific to the COI Module from cache
        /// </summary>
        private void UncacheInterModuleNavigationDetails()
        {
            Hashtable incomingData = pageCachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;
            if (incomingData != null)
            {
                if (incomingData.ContainsKey(Keys.FullNameKey))
                {
                    incomingData.Remove(Keys.FullNameKey);
                }
                if (incomingData.ContainsKey(Keys.AdmPersonIdKey))
                {
                    incomingData.Remove(Keys.AdmPersonIdKey);
                }
            }
            UncacheCOIDetails();
        }

        /// <summary>
        /// Removes COI and COI Id from cache
        /// </summary>
        private void UncacheCOIDetails()
        {
            Hashtable incomingData = pageCachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;
            if (incomingData != null)
            {
                if (incomingData.ContainsKey(Keys.COIIdKey))
                {
                    incomingData.Remove(Keys.COIIdKey);
                }
            }

            UncacheIntraModuleNavigationDetails();

            coi = cachePolicy.GetCachedObject(ConflictOfInterest.COIKey) as ConflictOfInterest;
            if (coi != null)
            {
                coi.UnCache();
            }
        }

        /// <summary>
        /// Removes all the details specific to the page from cache
        /// </summary>
        private void UncacheIntraModuleNavigationDetails()
        {
            Hashtable incomingData = pageCachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;
            if (incomingData != null)
            {
                if (incomingData.ContainsKey(Keys.QuesionnaireAnswerIdKey))
                {
                    incomingData.Remove(Keys.QuesionnaireAnswerIdKey);
                }
                if (incomingData.ContainsKey(Keys.QuestionnaireVersionIdKey))
                {
                    incomingData.Remove(Keys.QuestionnaireVersionIdKey);
                }
                if (incomingData.ContainsKey(Keys.ShowAsPopUp))
                {
                    incomingData.Remove(Keys.ShowAsPopUp);
                }
            }
            coi = cachePolicy.GetCachedObject(ConflictOfInterest.COIKey) as ConflictOfInterest;
            if (coi != null)
            {
                coi.QuestionnaireAnswers = null;
            }
        }

        /// <summary>
        /// Caches outgoing data key for use across pages.
        /// </summary>
        /// <param name="showTargetAsPopUp">set to true, if the target page is to be shown as a popup</param>
        /// <param name="qaId">Id of the QuestionnaireAnswer </param>
        /// <param name="qvId">Id of the QuestionnaireVersion</param>
        private void CacheOutGoingData(bool showTargetAsPopUp, int qaId, int qvId)
        {
            Hashtable outgoingData = pageCachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;

            outgoingData[Keys.ShowAsPopUp] = showTargetAsPopUp;
            if (qvId != 0)
            {
                outgoingData[Keys.QuestionnaireVersionIdKey] = qvId;
            }
            if (qaId != 0)
            {
                outgoingData[Keys.QuesionnaireAnswerIdKey] = qaId;
            }
            pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
        }

        /// <summary>
        /// Validate COI (checks the availablity of answers for all the required questionnaire items
        /// in the questionnaires and runs the validation script) and displays the user interface accordingly
        /// </summary>
        private void Submit()
        {
            annunciator.Message = string.Empty;
            CurrentConflictOfInterest.LoadQuestionnaireAnswers();
            foreach (QuestionnaireAnswer qA in CurrentConflictOfInterest.QuestionnaireAnswers)
            {
                QuestionnaireVersion questionnaireVersion = qA.QuestionnaireVersion;
                //Run the submission script
                Script submissionScript =
                    (Script) questionnaireVersion.Scripts[FormsManagement.Constants.ScriptType.Submission];

                if (submissionScript != null && submissionScript.ScriptText != null)
                {
                    using (ScriptEngineHost scriptHost =
                        new ScriptEngineHost
                            ("SubmissionScript://Scripting/" + questionnaireVersion.Id, "SubmissionScript", true))
                    {
                        ArrayList refs = ScriptReference.GetAllScriptReferences(DataAccess.GetConnectionString());

                        for (int i = 0; i < refs.Count; ++i)
                        {
                            ScriptReference reference = (ScriptReference) refs[i];
                            scriptHost.AddDLLReference(reference.Path);
                        }

                        // add the connection string
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ConnectionString,
                            DataAccess.GetConnectionString());
                        // add the caching policy
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.CachePolicy, cachePolicy);
                        // add this COI as an intrinsic.
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.COI, CurrentConflictOfInterest);
                        // add the QuestionnaireAnswer
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.QuestionnaireAnswer, qA);

                        try
                        {
                            if (scriptHost.Compile(submissionScript))
                            {
                                scriptHost.RunScript(submissionScript, "SubmissionScript.Script", "Main");
                            }
                        }
                        catch (Exception ex)
                        {
                            ExceptionReport.WriteToEventLog("Failed to submit COI", ex, true, ExceptionReport.ReportType.Error);
                            throw;
                        }
                    }
                }
            }
            CurrentConflictOfInterest.Status = Constants.COIStatus.Submitted;
            UserContext userContext = ((UserContext) cachePolicy.GetCachedObject(UserContext.CacheKey));
            if (CurrentConflictOfInterest.AdmPersonId != userContext.PersonId)
            {
                CurrentConflictOfInterest.FwkDomainUserId = userContext.DomainUserId;
            }
            CurrentConflictOfInterest.Save(DataAccess.ConnectionString, Constants.COIDateType.SubmittedDate, Server.MapPath(""));
            //Auditing the COI Submission.
            if (!CurrentConflictOfInterest.IsCOIReOpened)
            {
                CurrentConflictOfInterest.AuditCOIChanges(Constants.COIActionsForAudit.Submit);
            }
            else
            {
                CurrentConflictOfInterest.AuditCOIChanges(Constants.COIActionsForAudit.ReSubmit);
            }
            //Creating the Real time updates COI
            COICollection.AddNewCOI(cachePolicy,CurrentConflictOfInterest.AdmPersonId,Constants.COIDateType.None,Constants.COIType.RealTimeUpdate,string.Empty);
            SendSubmittedEmail(userContext);
            SetSubmissionStage(SubmissionStage.SubmitComplete);
        }

        /// <summary>
        /// Send an email to the user confirming that their COI has been submitted.
        /// </summary>
        /// <param name="userContext"></param>
        private void SendSubmittedEmail(UserContext userContext)
        {
            Person person = new Person(cachePolicy);
            person.Load(DataAccess.ConnectionString, userContext.PersonId);

            if (string.IsNullOrEmpty(person.Email))
            {
                throw new Exception("Email address not found.");
            }

            MailMessage message = new MailMessage(Settings.GetKeyValue("Email.COI.Admin", string.Empty), person.Email);

            ICachePolicy applicationCachePolicy = (ICachePolicy) Application[Names.ApplicationCachePolicyKey];
            RefCodes refCodes = (RefCodes) applicationCachePolicy.GetCachedObject(RefCodes.CacheKey);
            RefCode refCode = refCodes.GetRefCode(Constants.NotificationTypes.Domain, Constants.NotificationTypes.Submitted);

            message.Subject = refCode.Meaning;

            COIEMailTemplate emailTemplate = new COIEMailTemplate(cachePolicy);
            emailTemplate.Load(DataAccess.ConnectionString, Constants.NotificationTypes.Submitted);
            message.Body = emailTemplate.BodyText;
            message.IsBodyHtml = true;
            SmtpClient client = new SmtpClient(Settings.GetKeyValue("Email.SMTPServer", "127.0.0.1"));
            client.Send(message);
        }

        /// <summary>
        /// Displays an error message on the screen to the user with the exception, and all
        /// inner exception messages.
        /// </summary>
        /// <param name="ex">The exception to report on</param>
        private void DisplayExceptionReport(Exception ex)
        {
            annunciator.Title = InsightUtilities.Constants.Annunciator.Title;
            annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
        }

        #endregion

        #region Control Event Handlers

        /// <summary>
        /// Resets the subnavigation selected link before the header or the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                coiSubNavigation.Reset();
                coiSubModNavigation.Reset();
                UncacheInterModuleNavigationDetails();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link before the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnBreadCrumbNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                coiSubModNavigation.Reset();
                UncacheCOIDetails();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Uncache user details
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnCOISubModNavigationNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                UncacheIntraModuleNavigationDetails();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Validates COI and submits, if no errors are found
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnSubmit(object sender, ImageClickEventArgs e)
        {
            try
            {
                //Allow submitting only the Annual COI's
                if (CurrentConflictOfInterest.COIType == (int)Constants.COIType.RealTimeUpdate)
                {
                    throw new Exception("You are not allowed to submit a Real time updates COI.");
                }
                
                string passwordEntry;
                string userNameEntry = userName.Text.Trim();

                if (userNameEntry.Length == 0)
                {
                    throw new Exception("You must specify a user name");
                }

                UserContext userContext = cachePolicy.GetCachedObject(UserContext.CacheKey) as UserContext;
                if (userNameEntry.ToUpper() != userContext.Username.Trim().ToUpper())
                {
                    throw new Exception("User name should match with the logged in user");
                }

                if (Settings.GetKeyValue("ADAuthentication", false))
                {
                    passwordEntry = password.Text.Trim();
                    if (passwordEntry.Length == 0)
                    {
                        throw new Exception("You must specify a password");
                    }

                    Authenticator.ValidateCredentials(userNameEntry, passwordEntry);
                }

                Submit();
                helpContainer.Visible = false;

                /* Remove postbacks from ViewReport and ViewDisclosure*/
                viewApplication.OnClientClick = "javascript:window.open('../Research/DownloadForm.aspx?Report=ViewReport&CoiId=" + CurrentConflictOfInterest.Id + "&DocId=" + CurrentConflictOfInterest.DocumentId + "', 'ViewReport', 'resizable=yes, status=yes, scrollbars=yes');return false;";
                viewDisclosure.OnClientClick = "javascript:window.open('../Research/DownloadForm.aspx?Report=ViewDisclosure&CoiId=" + CurrentConflictOfInterest.Id + "&DocId=" + CurrentConflictOfInterest.DocumentId + "', 'ViewDisclosure', 'resizable=yes, status=yes, scrollbars=yes');return false;";
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        #endregion
    }
}